#include "CacheSimulator.h"

CacheSimulator::CacheSimulator(CacheProperties &instrCacheProp, CacheProperties &dataCacheProp, std::string fileName) :
	  instructionCache(getCacheType(instrCacheProp)), 
	  dataCache(getCacheType(dataCacheProp)), 
	  parser(fileName), instructionHitCounter(0), instructionMissCounter(0), dataHitCounter(0), dataMissCounter(0)
{
}

CacheSimulator::~CacheSimulator()
{
	if(instructionCache != 0)
	{
		delete instructionCache;
		instructionCache = 0;
	}

	if(dataCache != 0)
	{
		delete dataCache;
		dataCache = 0;
	}
}

void CacheSimulator::read()
{
	Parser::TraceElement *currentElement = parser.readNextElement();

	while(currentElement)
	{
		computeLine(*currentElement);
		currentElement = parser.readNextElement();
	}

	std::cout << "Data: Hit = " << dataHitCounter << " | Miss = " << dataMissCounter << std::endl;
	std::cout << "Data Cache is " << (int)(dataCache->getFilled() * 100) << "% Full" << std::endl;
	std::cout << "Instruction: Hit = " << instructionHitCounter << " | Miss = " << instructionMissCounter << std::endl;
	std::cout << "Instruction Cache is " << (int)(instructionCache->getFilled() * 100) << "% Full" << std::endl;
}

Cache *CacheSimulator::getCacheType(CacheProperties properties)
{
	switch(properties.associativity)
	{
	case FullyAssociative:
		return new FullyAssociativeCache(properties.size, properties.cacheLineSize);
	case SetAssociative:
		return new SetAssociativeCache(properties.size, properties.cacheLineSize);
	default:
		return new DirectMappedCache(properties.size, properties.cacheLineSize);
	}
}

void CacheSimulator::computeLine(Parser::TraceElement &element)
{
	switch(element.type)
	{
	case Parser::TraceType::I: //instruction read
		instructionCache->performCacheOperation(element, instructionHitCounter, instructionMissCounter);
	default: //data operation
		dataCache->performCacheOperation(element, dataHitCounter, dataMissCounter);
	}
}